/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package tal.drivechain.gui;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import tal.drivechain.system.Globals;

/**
 *
 * @author Main
 */
public class OSDPrinter {
    private TransparentFrame frame;
    private OSDText osdText;

    public OSDPrinter(Font osdFont, String message, long duration, Color color)  throws Exception {
        frame = new TransparentFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);
        frame.setUndecorated(true);
        osdText = new OSDText(frame);
        osdText.setFont(osdFont);
        osdText.setColor(color);
        frame.getContentPane().add(osdText);
        osdText.setText(message);
        show();
        (new CloseThread(duration, frame)).start();
    }

    public void show() {
        frame.resetUnderImg();
        frame.setVisible(true);
    }

    public void hide() {
        frame.setVisible(false);
    }

    public void close() {
        frame.setVisible(false);
        frame.dispose();
    }

}


class CloseThread extends Thread {
    private long delay;
    private JFrame m;
    
    public CloseThread(long delay, JFrame frame) {
        this.delay = delay;
        this.m = frame;
    }
    
    @Override
    public void run() {
        synchronized(this) {
            try {
                this.wait(delay);
            } catch (InterruptedException ie) { return; }
        }
        m.setVisible(false);
        m.dispose();
    }

}


class TransparentFrame extends JFrame {
    Robot robot;
    BufferedImage screenImg;
    Rectangle screenRect;
    MyPanel contentPanel=new MyPanel();
    boolean userActivate=false;
    
    public TransparentFrame() {
        super();
        createScreenImage();
        this.setContentPane(contentPanel);
        if (Globals.getOS()==Globals.OS.Mac) this.setBackground(new Color(0,0,0,0));
        this.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentMoved(ComponentEvent e) {
                resetUnderImg();
                repaint();
            }
            
            @Override
            public void componentResized(ComponentEvent e) {
                resetUnderImg();
                repaint();
            }
            
            @Override
            public void componentShown(ComponentEvent e) {
                resetUnderImg();
                repaint();
            }
        });
        
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowActivated(WindowEvent e) {
                if (userActivate) {
                    userActivate=false;
                    TransparentFrame.this.setVisible(false);
                    createScreenImage();
                    resetUnderImg();
                    TransparentFrame.this.setVisible(true);
                }
                else {
                    userActivate=true;
                }
            }
        });
    }
 
    protected void createScreenImage() {
        if (Globals.getOS()==Globals.OS.Mac) return;
        try {
            if (robot==null)
                robot=new Robot();        
        }
        
        catch (AWTException ex) {
            ex.printStackTrace();
        }
        Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
        screenRect=new Rectangle(0,0,screenSize.width,screenSize.height);
        screenImg=robot.createScreenCapture(screenRect);
    }
 
    public void resetUnderImg() {
        if (Globals.getOS()==Globals.OS.Mac) return;
        if (robot!=null && screenImg!=null) {
            Rectangle frameRect=getBounds();
            int x=frameRect.x;
            contentPanel.paintX=0;
            contentPanel.paintY=0;
            if (x<0) {
                contentPanel.paintX=-x;
                x=0;
            }
            int y=frameRect.y;
            if (y<0) {
                contentPanel.paintY=-y;
                y=0;
            }
            int w=frameRect.width;
            if (x+w>screenImg.getWidth())
                w=screenImg.getWidth()-x;
            int h=frameRect.height;
            if (y+h>screenImg.getHeight())
                h=screenImg.getHeight()-y;
            contentPanel.underFrameImg=screenImg.getSubimage(x,y,w,h);
        }
    }
}
class MyPanel extends JPanel {
    BufferedImage underFrameImg;
    int paintX=0;
    int paintY=0;
    
    public MyPanel() {
        super();
        setOpaque(true);
        setBackground(new Color(0,0,0,0));
    }
    
    @Override
    public void paint(Graphics g) {
        super.paint(g);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        if (Globals.getOS()!=Globals.OS.Mac) g.drawImage(underFrameImg,paintX,paintY,null);
        super.paintComponent(g);
    }
}

class OSDText extends JPanel {
    private Font font;
    private String message;
    private Color color;
    private JFrame frame;

    public OSDText(JFrame frame) {
        super();
        this.frame = frame;
        this.setOpaque(false);
    }

    Dimension calculateSize() {
        double width = (int) (font.getStringBounds(message, new FontRenderContext(null, false, false)).getWidth() + 15);
        double height = font.getStringBounds(message, new FontRenderContext(null, false, false)).getHeight()+15;
        return new Dimension((int)Math.round(width), (int)Math.round(height));
    }

    @Override
    public void setFont(Font font) {
        this.font = font;
    }

    void setColor(Color color) {
        this.color = color;
        repaint();
    }

    void setText(String message) {
        this.message = message;
        Dimension size = calculateSize();
        this.setSize(size);
        this.setPreferredSize(size);
        this.setMaximumSize(size);
        this.setMinimumSize(size);
        double x = Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2 - (size.width/2);
        double y = Toolkit.getDefaultToolkit().getScreenSize().getHeight() - size.height - 100;
        frame.setBounds((int)x,(int)y,(int)size.width,(int)size.height);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int width = getSize().width;
        int height = getSize().height;

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

        FontRenderContext frc = g2.getFontRenderContext();
        TextLayout textTl = new TextLayout(message, font, frc);
        AffineTransform transform = new AffineTransform();
        Shape outline = textTl.getOutline(null);
        Rectangle outlineBounds = outline.getBounds();
        transform = g2.getTransform();
        transform.translate(width / 2 - (outlineBounds.width / 2), height / 2
            + (outlineBounds.height / 2));
        g2.transform(transform);
        g2.setColor(color);
        g2.fill(outline);
        g2.setColor(Color.BLACK);
        g2.draw(outline);
        g2.setClip(outline);
    }
}
